package com.wimcorp.magic.client.input;

import java.rmi.RemoteException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.lang.StringUtils;
import org.fusesource.jansi.Ansi.Color;

import com.wimcorp.magic.client.CommandLineInterface;
import com.wimcorp.magic.exception.SystemException;
import com.wimcorp.magic.input.BehaviorInput;
import com.wimcorp.magic.input.Location;
import com.wimcorp.magic.input.Type;
import com.wimcorp.magic.userinterface.GameInterface;

public class DeclareBlockerSelector extends Selector implements Callable<Long[]> {

	private Set<String> types = new HashSet<>();
	private Set<String> locations = new HashSet<>();
	private Set<String> behaviors = new HashSet<>();
	private long attackerId;

	public DeclareBlockerSelector(CommandLineInterface commandLineInterface, long attackerId) {
		super(commandLineInterface);
		this.attackerId = attackerId;
		types.add(Type.CREATURE.toString());
		locations.add(Location.BATTLEFIELD.toString());
		behaviors.add(BehaviorInput.NOT_TAPPED.toString());
	}

	public Long[] call() {
		return select(types, locations, behaviors);
	}

	private Long[] select(Set<String> types, Set<String> locations, Set<String> behaviors) {
		Options options = getSelectOptions(types, locations, behaviors);
		String message = "Select " + getArrayString(types) + " to block : ";

		ConsoleInput selectConsole = new ConsoleInput();
		ConsoleInput mainConsole = getCommandLineInterface().getMainConsole();
		CommandLineParser parser = new DefaultParser();
		Set<Long> results = new HashSet<>();
		setRun(true);
		while (isRun()) {
			mainConsole.cancel();
			getCommandLineInterface().printInstruction(message);
			Long result = null;
			try {
				CommandLine line = parser.parse(options, selectConsole.readLine().split(" "));
				for (Option option : line.getOptions()) {
					if ("s".equals(option.getOpt())) {
						result = select(option);
					} else if ("vbl".equals(option.getOpt())) {
						viewBlockers(results);
					} else {
						result = processCommands(options, line.getOptions());
					}
				}
				if (result > 0) {
					getCommandLineInterface().message(
							String.format(
									"You block with %s.",
									getCommandLineInterface().getGame().getCardName(
											getCommandLineInterface().getPlayerName(), result)));
					results.add(result);
				}
			} catch (Exception e) {
				getCommandLineInterface().print(e.getMessage(), Color.RED);
			}
		}
		synchronized (mainConsole.getLock()) {
			mainConsole.getLock().notifyAll();
		}
		return results.toArray(new Long[results.size()]);
	}

	private Long select(Option option) throws RemoteException, SystemException {
		Long result = null;
		String input = option.getValue();
		String playerName = getCommandLineInterface().getPlayerName();
		GameInterface game = getCommandLineInterface().getGame();
		if (StringUtils.isNumeric(input)) {
			long identifier = new Long(input);
			result = game.validateInput(playerName, types, locations, behaviors, identifier);
			if (result != -1) {
				if (!game.canBlock(playerName, result, attackerId)) {
					throw new SystemException(String.format("This creature can't block %s.",
							game.getOpponentCardName(playerName, attackerId)));
				}
			} else {
				throw new SystemException("No " + getArrayString(types) + " in " + getArrayString(locations) + " with "
						+ getArrayString(behaviors) + " id : " + input + ". ");
			}
		}
		return result;
	}

	protected void viewBlockers(Set<Long> results) throws RemoteException {
		String card = getCommandLineInterface().getGame().viewCard(
				getCommandLineInterface().getGame().getOpponent(getCommandLineInterface().getPlayerName()), attackerId);
		getCommandLineInterface().print("------------- Attacker -------------", Color.WHITE);
		getCommandLineInterface().print(card, Color.WHITE);
		getCommandLineInterface().print("------------- Blockers -------------", Color.WHITE);
		for (Long id : results) {
			card = getCommandLineInterface().getGame().viewCard(getCommandLineInterface().getPlayerName(), id);
			getCommandLineInterface().print(card, Color.WHITE);
		}
		if (results.size() == 0) {
			getCommandLineInterface().print("None", Color.WHITE);
		}
	}

	public Options getSelectOptions(Set<String> types, Set<String> locations, Set<String> behaviors) {
		Options options = new Options();
		options.addOption(getHelpOption());
		options.addOption(getDoneOption());
		options.addOption(getDelcareBlockerOption(types, locations));
		options.addOption(getActivateAbilitiesOption());
		options.addOption(getPlayerListOption());
		options.addOption(getViewAttackersOption());
		options.addOption(getViewBattleFieldOption());
		options.addOption(getViewBlockersdOption());
		options.addOption(getViewGraveyardOption());
		options.addOption(getViewHandOption());
		options.addOption(getViewLifeOption());
		return options;
	}

}
